package com.sky.service.impl;

import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.OrdersSubmitDTO;
import com.sky.entity.AddressBook;
import com.sky.entity.OrderDetail;
import com.sky.entity.Orders;
import com.sky.entity.ShoppingCart;
import com.sky.exception.AddressBookBusinessException;
import com.sky.mapper.AddressBookMapper;
import com.sky.mapper.OrderDetailMapper;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.ShoppingCardMapper;
import com.sky.service.OrderService;
import com.sky.vo.OrderSubmitVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.beans.Transient;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    private final OrderMapper orderMapper;

    private final OrderDetailMapper orderDetailMapper;

    private final AddressBookMapper addressBookMapper;

    private final ShoppingCardMapper shoppingCardMapper;

    public OrderServiceImpl(OrderMapper orderMapper, OrderDetailMapper orderDetailMapper1, AddressBookMapper addressBookMapper, ShoppingCardMapper shoppingCardMapper) {
        this.orderMapper = orderMapper;
        this.orderDetailMapper = orderDetailMapper1;
        this.addressBookMapper = addressBookMapper;
        this.shoppingCardMapper = shoppingCardMapper;
    }

            /**
     * 提交订单 - 处理用户下单的完整业务流程
     *
     * @param ordersSubmitDTO 订单提交数据传输对象，包含用户选择的地址簿ID、配送备注、预计送达时间等信息
     * @return OrderSubmitVO 订单提交成功后的响应视图对象，包含新创建订单的关键信息
     * @throws AddressBookBusinessException 当地址簿信息不存在或购物车为空时抛出业务异常
     */
    @Override
    @Transient
    public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {
        // 记录用户下单操作日志，便于后续问题追踪和业务分析
        log.info("用户下单：{}", ordersSubmitDTO);

        // 第一步：验证并获取用户选择的收货地址信息
        // 从订单提交参数中提取地址簿ID，查询对应地址详情
        Long addressBookId = ordersSubmitDTO.getAddressBookId();
        AddressBook addressBook = addressBookMapper.getById(addressBookId);
        // 如果地址簿记录不存在，则抛出业务异常，中断下单流程
        if (addressBook == null) {
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }

        // 第二步：获取当前用户的购物车商品列表，作为订单商品来源
        // 创建购物车查询条件对象，设置当前用户ID进行数据筛选
        ShoppingCart cart = new ShoppingCart();
        Long userId = BaseContext.getCurrentId(); // 从线程上下文中获取当前登录用户ID
        cart.setUserId(userId);
        // 查询该用户购物车中的所有商品项，这些将成为订单的商品明细
        List<ShoppingCart> cartList = shoppingCardMapper.list(cart);
        // 若购物车为空则无法下单，抛出相应业务异常提示用户
        if (cartList == null || cartList.isEmpty()) {
            throw new AddressBookBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }

        // 第三步：构建订单主表信息并保存至数据库
        // 创建订单实体对象，用于存储订单的基本信息
        Orders orders = new Orders();
        // 使用BeanUtils工具类快速复制DTO中的基础属性到订单实体（如配送备注、预计送达时间等）
        BeanUtils.copyProperties(ordersSubmitDTO, orders);
        // 设置订单关联的用户ID，确保订单归属正确
        orders.setUserId(userId);
        // 设置订单创建时间，标记下单的具体时刻
        orders.setOrderTime(LocalDateTime.now());
        // 初始化订单支付状态为"未支付"(UN_PAID)，等待用户完成支付
        orders.setPayStatus(Orders.UN_PAID);
        // 初始化订单状态为"待付款"(PENDING_PAYMENT)，表示订单已创建但尚未支付
        orders.setStatus(Orders.PENDING_PAYMENT);
        // 生成唯一的订单编号，采用时间戳确保全局唯一性
        orders.setNumber(String.valueOf(System.currentTimeMillis()));
        // 从地址簿中提取联系电话，填充到订单联系信息中
        orders.setPhone(addressBook.getPhone());
        // 从地址簿中提取收货人姓名，填充到订单联系信息中
        orders.setConsignee(addressBook.getConsignee());
        // 从地址簿中提取详细地址，包括省市区街道等完整地址信息
        orders.setAddress(addressBook.getDetail());
        // 将完整的订单主表信息插入数据库，获得订单ID用于后续操作


        orderMapper.insert(orders);

        // 第四步：构建订单详情列表并批量保存至数据库
        // 创建订单详情集合，用于存储当前订单的所有商品明细
        List<OrderDetail> details = new ArrayList<>();
        // 遍历购物车中的每一项商品，转换为订单详情记录
        for (ShoppingCart shoppingCart : cartList) {
            // 为每个购物车项目创建对应的订单详情实体
            OrderDetail orderDetail = new OrderDetail();
            // 使用BeanUtils复制购物车项目的共有属性（如商品名称、数量、价格等）到订单详情
            BeanUtils.copyProperties(shoppingCart, orderDetail);
            // 设置订单详情关联的订单ID，建立与订单主表的外键关系
            orderDetail.setOrderId(orders.getId());
            // 将构建好的订单详情添加到详情列表中
            details.add(orderDetail);
        }
        // 批量插入所有订单详情记录，提高数据库操作效率
        orderDetailMapper.insertBatch(details);


        shoppingCardMapper.cleanByUserId(userId);
        // 第五步：构建并返回订单提交成功的响应结果
        // 使用建造者模式创建订单提交结果视图对象，返回给前端展示关键订单信息
        return OrderSubmitVO.builder()
                // 返回数据库生成的订单主键ID，用于后续订单查询和操作
                .id(orders.getId())
                // 返回生成的订单编号，供用户查看和识别订单
                .orderNumber(orders.getNumber())
                // 返回订单总金额，显示本次消费的费用
                .orderAmount(orders.getAmount())
                // 返回订单创建时间，告知用户下单的具体时刻
                .orderTime(orders.getOrderTime())
                .build();
    }


}
